-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Segment Tree Beats #90
base: main
Are you sure you want to change the base?
Conversation
chihhsi
commented
Jun 21, 2023
•
edited
Loading
edited
- Read Contribute to NTHU-CPP.
- Rebase to the latest main branch.
- List all the references.
- Successfully build the website by mdBook with no error after the change.
- Exclude any irrelevant files.
- Link to the issue which is related to your change.
- Review the content by myself.
- Pass tests/CI.
@harry900831 Waiting review |
src/data_structure/intro.md
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't have to add this file
<img src="image/segment_tree_beats/1-0.jpg" width="600" style="display:block; margin: 0 auto;"/> | ||
|
||
從根節點 \\( 4 | 3 \\) 出發向下走,遇到左子節點 \\( 2 | 1 \\),由於 \\( mx1 \leq 2 \\),屬於情況一,直接退出;遇到右子節點 \\( 4 | 3 \\),由於 \\( mx2 \geq 2 \\),屬於情況三,對子節點進行遞迴搜尋。 | ||
|
||
<img src="image/segment_tree_beats/1-1.jpg" width="600" style="display:block; margin: 0 auto;"/> | ||
|
||
繼續從右子節點 \\( 4 | 3 \\) 向下遞迴搜尋,遇到左子節點 \\( 4 | -1 \\),由於 \\( mx2 < 2 < mx1 \\),屬於情況二,區間和被改為 \\( 4 + 1 \cdot (2 - 4) = 2 \\),最大值被更新為 \\( 2 \\),標記也被設為 \\( 2 \\);遇到右子節點 \\( 4 | -1 \\),由於 \\( mx2 < 2 < mx1 \\),屬於情況二,同理。 | ||
|
||
<img src="image/segment_tree_beats/1-2.gif" width="600" style="display:block; margin: 0 auto;"/> | ||
|
||
接著向上更新標記,節點 \\( 4 | 3 \\) 的區間和更新為 \\( 2 + 2 = 4 \\),最大值更新為 \\( 2 \\),最小值更新為 \\( -1 \\)。 | ||
|
||
<img src="image/segment_tree_beats/1-3.gif" width="600" style="display:block; margin: 0 auto;"/> | ||
|
||
最後向上更新標記,根節點 \\( 4 | 3 \\) 的區間和更新為 \\( 2 + 2 = 4 \\),最大值更新為 \\( 2 \\),最小值更新為 \\( max(1, -1) = 1 \\)。 | ||
|
||
<img src="image/segment_tree_beats/1-4.gif" width="600" style="display:block; margin: 0 auto;"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這裡都講太細了
沒有這個必要
|
||
如下圖所示,左圖是一棵建立在 \\( [1, 4] \\) 上的線段樹,每一個節點紀錄的資訊的左側是區間最大值,右側是嚴格次大值。現在我們要讓區間 \\( [1, 4] \\) 對 \\( 2 \\) 取 \\( min \\)。那麼左圖中紅色邊表示搜尋時經過的邊,紅色字體的節點表示搜索終止的節點,右圖為更新後的線段樹。 | ||
|
||
<img src="image/segment_tree_beats/update_min.gif" width="600" style="display:block; margin: 0 auto;"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
你把以下的圖濃縮到這一張內 就好
因為這一個演算法沒有很難懂,難的事他的時間複雜度為什麼是對的
2. 考慮一次標記下傳,只讓標記類 \\( T \\) 的權值 \\( w(T) \\) 增加 \\( O(1) \\)。 | ||
3. 當 \\( mx2 \geq x \\) 時,也就是情況三發生時,要進行遞迴搜尋,因為父節點的標記一定跟其中一個子節點一樣,所以每到一個節點至少回收一個標記,那麼 \\( \Phi(x) \\) 減少了 \\( O(1) \\)。 | ||
|
||
<img src="image/segment_tree_beats/2-4.gif" width="600" style="display:block; margin: 0 auto;"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我覺得你的 gif 都動好快,可以考慮每一張圖片放慢一點
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
然後看有沒有什麼方式讓讀者知道 現在是從新開始了
```cpp | ||
struct STB { | ||
#define ls (u << 1) | ||
#define rs (u << 1 | 1) | ||
|
||
struct Node { | ||
ll sum; | ||
int l, r, mx1, mx2, cmx, tag; | ||
} T[N << 2]; | ||
|
||
void pushup(int u) { // 向上更新標記 | ||
T[u].sum = T[ls].sum + T[rs].sum; | ||
if (T[ls].mx1 == T[rs].mx1){ | ||
T[u].mx1 = T[ls].mx1; | ||
T[u].cmx = T[ls].cmx + T[rs].cmx; | ||
T[u].mx2 = max(T[ls].mx2, T[rs].mx2); | ||
} else if (T[ls].mx1 > T[rs].mx1) { | ||
T[u].mx1 = T[ls].mx1; | ||
T[u].cmx = T[ls].cmx; | ||
T[u].mx2 = max(T[ls].mx2, T[rs].mx1); | ||
} else { | ||
T[u].mx1 = T[rs].mx1; | ||
T[u].cmx = T[rs].cmx; | ||
T[u].mx2 = max(T[ls].mx1, T[rs].mx2); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove Chinese comment for template code
struct Node { | ||
ll sum; | ||
int l, r, mx1, mx2, cmx, tag; | ||
} T[N << 2]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is N << 2 enough? I'm curious
@harry900831 Waiting review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Please revise the proof by potential method to make it more clear
- You may refer to others PR or the article that has been merged into NTHU-CPP to know that what kind of article you have to write.
- https://nthu-cp.github.io/NTHU-CPP/graph/lca.html
- https://nthu-cp.github.io/NTHU-CPP/math/introduction_to_generating_function.html
- https://nthu-cp.github.io/NTHU-CPP/graph/introduction_to_AP_bridge.html
- https://nthu-cp.github.io/NTHU-CPP/graph/introduction_to_BCC.html
- https://nthu-cp.github.io/NTHU-CPP/greedy/basic.html
- https://nthu-cp.github.io/NTHU-CPP/sqrt/sqrt_decomposition.html
- Please fix markdownlint and textlint.
- There should be two section
- Example problem: you should explain the problem in detail (including problem description, solution, code, time complexity/correctness analysis...). Also, please solve these problem with your own template code that mention above.
- Exercise problem: a problem list that reader may do if they want to practice treap, you don't have to explain these problem in detail, you may provide hint only.
- Please reorganize the section, since you have more time now. You may mention more technique / trick about segment tree beats
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/data_structure/image/segment_tree/segment_tree_beats/.......
|
||
Segment Tree Beats(簡稱 STB)是北京大學的吉如一提出的概念,發表在《区间最值操作与历史最值问题》[^note-1]中。 | ||
|
||
STB 可以滿足下列兩項性質: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這邊用滿足下列兩項性質有點怪
|
||
考慮下面這一種解法: | ||
|
||
對線段樹每一個節點除了維護區間和 \\( sum \\) 之外,還要額外維護區間中的最大值 \\( mx1 \\),嚴格次大值 \\( mx2 \\) 以及最大值個數 \\( cmx \\)。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
線段樹每一個節點除了維護區間和 \( sum \)、區間最大值 \( mx1 \) 之外,還要額外維護嚴格次大值 \( mx2 \) 以及最大值個數 \( cmx \)。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
因此第二三種操作就是普通線段數直接更新就好
現在讓我們考慮第一種操作
#### 歷史最大值 | ||
|
||
當前位置下曾經出現過的數的最大值。定義一個輔助數組 \\( B \\),最開始 \\( B \\) 數組與 \\( A \\) 數組完全相同。在每一次操作後,對每一個 \\( i \in [1, n] \\),我們都進行一次更新,讓 \\( B_i = max(B_i, A_i) \\)。這時,我們將 \\( B_i \\) 稱作 \\( i \\) 這個位置的歷史最大值。 | ||
|
||
<img src="image/segment_tree_beats/6-1.jpg" width="500" style="display:block; margin: 0 auto;"/> | ||
|
||
#### 歷史最小值 | ||
|
||
當前位置下曾經出現過的數的最小值。定義一個輔助數組 \\( B \\),最開始 \\( B \\) 數組與 \\( A \\) 數組完全相同。在每一次操作後,對每一個 \\( i \in [1, n] \\),我們都進行一次更新,讓 \\( B_i = min(B_i, A_i) \\)。這時,我們將 \\( B_i \\) 稱作 \\( i \\) 這個位置的歷史最小值。 | ||
|
||
<img src="image/segment_tree_beats/6-2.jpg" width="500" style="display:block; margin: 0 auto;"/> | ||
|
||
#### 歷史版本和 | ||
|
||
定義一個輔助數組 \\( B \\),最開始 \\( B \\) 數組中的所有數都是 \\( 0 \\)。在每一次操作後,對每一個 \\( i \in [1, n] \\),我們都進行一次更新,讓 \\( B_i \\) 加上 \\( A_i \\)。這時,我們將 \\( B_i \\) 稱作 \\( i \\) 這個位置的歷史版本和。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
沒有講解這些操作怎麼處理?
> 例題 2. [Tyvj - CPU 監控](http://www.tyvj.cn/p/1518) | ||
> | ||
> 給一個長度為 \\( n \\) 的序列 \\( A \\),同時定義一個輔助數組 \\( B \\),\\( B \\)開始與 \\( A \\) 完全相同。接下來對其進行 \\( m \\) 筆操作,操作有四種: | ||
> | ||
> 1. 給定 \\( L, R, x \\),對所有 \\( i \in [L, R] \\),將 \\( A_i \\) 修改成 \\( x \\)。 | ||
> 2. 給定 \\( L, R, x \\),對所有 \\( i \in [L, R] \\),將 \\( A_i \\) 加上 \\( x \\)。 | ||
> 3. 給定 \\( L, R \\),對所有 \\( i \in [L, R] \\),輸出 \\( A_i \\) 的最大值。 | ||
> 4. 給定 \\( L, R \\),對所有 \\( i \in [L, R] \\),輸出 \\( B_i \\) 的最大值。 | ||
> | ||
> - \\( n, m \leq 10^5 \\) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這題目敘述沒錯嗎?
沒有提到怎樣會更改到B啊
|
||
### 可以用懶標記處理的問題 | ||
|
||
> 例題 2. [Tyvj - CPU 監控](http://www.tyvj.cn/p/1518) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invalid link
Tyvj 又是什麼 oj?
能使用常用oj 就勁量使用常用oj
|
||
</details> | ||
|
||
### 歷史最值問題 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這個章節需要重新organize
Please resolve the conversation if you fix it~ |
src/data_structure/image/segment_tree/segment_tree_beats/1-1.gif
Outdated
Show resolved
Hide resolved
|
||
<img src="image/segment_tree/segment_tree_beats/3-2.gif" width="700" style="display:block; margin: 0 auto;"/> | ||
|
||
最後讓區間 \\( [4, 4] \\) 的元素加上 \\( 1 \\)。階層為 \\( 2 \\) 的右邊節點下傳區間加標記,接著發現其左子節點的 \\( mx2 < 3 < mx1 \\),所以需要用 \\( 3 \\) 更新左子節點的最大值和最小值。 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
這部分看起來是會造成時間複雜度跟上一題不同的最大關鍵
但是單純看你上面的敘述想不到會這樣
@chihhsi Do you receive my discord message? |